#ifdef _DEBUG_
#include <iostream>
using namespace std;
#endif

#include "edaSeqWrapperControl.h"
#include "edaSeqSearchWrapper.h"

edaSeqWrapperControl::edaSeqWrapperControl() :
  edaWrapperControl()
{
}

bool edaSeqWrapperControl::search(edaSolution &sol)
{
  map<int, edaSolution*> taskSolution;
  int lastSearch;

  // If all job is done, quit
  while (!allDone())
  {
    // Find nodes that ready to run
    vector<int> readyNodes = findReadyNodes();
    vector<int>::iterator intIter;

    for (intIter = readyNodes.begin(); intIter != readyNodes.end(); intIter++)
    {
      vector<int> parentNodes;
      vector<int>::iterator parentIter;
      parentNodes = taskDAG.getParentNodes(*intIter);

      edaSearch *&sa = taskDAG[*intIter];
      lastSearch = *intIter;
      edaSolution *mysol = NULL;

      if (parentNodes.empty()){
        // No parent
        mysol = sol.clone();
      } else {
        // Have parents
        double bestFitness = -1e100;
        int bestSolution;
        for (parentIter = parentNodes.begin(); parentIter != parentNodes.end(); parentIter++)
        {
          double f = (taskSolution[*parentIter])->fullEvaluate();
          if (bestFitness < f)
          {
            bestFitness = f;
            bestSolution = *parentIter;
          }
        }

        mysol = taskSolution[bestSolution]->clone();
      }

#ifdef _DEBUG_
      cout << "[" << __FILE__ << ":" << __LINE__ << "] mysol(before): " 
           << mysol->fullEvaluate() << endl;
#endif

      // Pack the search algorithm
      edaBuffer sa_buf;
      sa->doSerialize( sa_buf, true );

      // Create wrapper object
      edaSearchWrapper *sw;
      sw = new edaSeqSearchWrapper( sa_buf );

      // Pack the solution
      edaBuffer sol_buf_in, sol_buf_out;
      mysol->doSerialize( sol_buf_in, true );

      // Invoke wrapper's search method
      sw->search( sol_buf_in, sol_buf_out );

      // Unpack the solution
      edaSolution *osol = (edaSolution*)classGenerateFromBuffer( sol_buf_out );

      // Destroy objects
      delete sw;
      delete mysol;
      mysol = osol;

      // save the new solution
      taskSolution[*intIter] = mysol;
      taskStatus[*intIter] = STATUS_FINISHED;

#ifdef _DEBUG_
      cout << "[" << __FILE__ << ":" << __LINE__ << "] - " << *intIter 
           <<  " -  mysol(after): " << mysol->fullEvaluate() << endl;
#endif
    }
  }

  // Return the solution
  sol = *(taskSolution[lastSearch]);

  // Delete solutions map
  map<int, edaSolution*>::iterator mapIter;
  for (mapIter = taskSolution.begin(); mapIter != taskSolution.end(); mapIter++)
  {
    delete mapIter->second;
  }

  return true;
}
